/*
 * KuhnMunkresProjectView.java
 */

package kuhnmunkresproject;

import java.awt.Color;
import java.awt.Graphics;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;

/**
 * The application's main frame.
 */
public class KuhnMunkresProjectView extends FrameView {

    public KuhnMunkresProjectView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;

            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");


        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {

                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }

                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();

                } else if ("message".equals(propertyName)) {
                    String text = (String)(evt.getNewValue());
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer)(evt.getNewValue());

                }
            }
        });
    }

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = KuhnMunkresProjectApp.getApplication().getMainFrame();
            aboutBox = new KuhnMunkresProjectAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        KuhnMunkresProjectApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jLayeredPane1 = new javax.swing.JLayeredPane();
        spNoElementos = new javax.swing.JSpinner();
        lblNoElementos = new javax.swing.JLabel();
        btnGenerar = new javax.swing.JButton();
        btnIniciar = new javax.swing.JButton();
        jLayeredPane2 = new javax.swing.JLayeredPane();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();

        mainPanel.setName("mainPanel"); // NOI18N

        jLayeredPane1.setName("jLayeredPane1"); // NOI18N

        spNoElementos.setName("spNoElementos"); // NOI18N
        spNoElementos.setBounds(110, 10, 50, 28);
        jLayeredPane1.add(spNoElementos, javax.swing.JLayeredPane.DEFAULT_LAYER);

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(kuhnmunkresproject.KuhnMunkresProjectApp.class).getContext().getResourceMap(KuhnMunkresProjectView.class);
        lblNoElementos.setText(resourceMap.getString("lblNoElementos.text")); // NOI18N
        lblNoElementos.setName("lblNoElementos"); // NOI18N
        lblNoElementos.setBounds(0, 10, 156, 18);
        jLayeredPane1.add(lblNoElementos, javax.swing.JLayeredPane.DEFAULT_LAYER);

        btnGenerar.setText(resourceMap.getString("btnGenerar.text")); // NOI18N
        btnGenerar.setName("btnGenerar"); // NOI18N
        btnGenerar.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnGenerar_Click(evt);
            }
        });
        btnGenerar.setBounds(170, 10, 73, 30);
        jLayeredPane1.add(btnGenerar, javax.swing.JLayeredPane.DEFAULT_LAYER);

        btnIniciar.setText(resourceMap.getString("btnIniciar.text")); // NOI18N
        btnIniciar.setName("btnIniciar"); // NOI18N
        btnIniciar.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnInicio_Click(evt);
            }
        });
        btnIniciar.setBounds(250, 10, 47, 30);
        jLayeredPane1.add(btnIniciar, javax.swing.JLayeredPane.DEFAULT_LAYER);

        jLayeredPane2.setName("jLayeredPane2"); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jLayeredPane2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 546, Short.MAX_VALUE)
                    .addComponent(jLayeredPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 546, Short.MAX_VALUE))
                .addContainerGap())
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jLayeredPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE)
                .addContainerGap())
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(kuhnmunkresproject.KuhnMunkresProjectApp.class).getContext().getActionMap(KuhnMunkresProjectView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        setComponent(mainPanel);
        setMenuBar(menuBar);
    }// </editor-fold>//GEN-END:initComponents

private void btnGenerar_Click(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnGenerar_Click
// TODO add your handling code here:
    int noElementos = Integer.parseInt(this.spNoElementos.getValue().toString());

    if(noElementos > 1)
    {
        this.campos = new JTextField[noElementos][noElementos];
        this.jLayeredPane2.removeAll();
        this.jLayeredPane2.repaint();
        //mTextField = new LinkedList<JTextField>();
        
        for(int i = 0; i < noElementos; i++)
        {
            for(int j = 0; j < noElementos; j++)
            {
                if(i == 0)
                {
                    JLabel lblTemp = new JLabel("Y" + (j + 1));
                    
                    lblTemp.setVisible(true);
                    lblTemp.setSize(20, 20);
                    lblTemp.setLocation((j + 1) * 30, 30);
                    
                    this.jLayeredPane2.add(lblTemp);
                }
                if(j == 0)
                {
                    JLabel lblTemp = new JLabel("X" + (i + 1));
                    
                    lblTemp.setVisible(true);
                    lblTemp.setSize(20, 20);
                    lblTemp.setLocation(0, (i + 2) * 30);
                    
                    this.jLayeredPane2.add(lblTemp);
                }
                
                this.campos[i][j] = new JTextField("0");
                this.campos[i][j].setVisible(true);
                this.campos[i][j].setSize(20, 20);
                this.campos[i][j].setLocation((j + 1) * 30, (i + 2) * 30);
                //mTextField.add(this.campos[i][j]);

                this.jLayeredPane2.add(this.campos[i][j]);
            }
        }
        
        //Datos de prueba
        if(noElementos==3)
        {
            this.campos[0][0].setText("160");
            this.campos[0][1].setText("110");
            this.campos[0][2].setText("100");
            
            this.campos[1][0].setText("100");
            this.campos[1][1].setText("160");
            this.campos[1][2].setText("110");
            
            this.campos[2][0].setText("110");
            this.campos[2][1].setText("30");
            this.campos[2][2].setText("90");
        }
        if(noElementos==5)
        {
            this.campos[0][0].setText("3");
            this.campos[0][1].setText("5");
            this.campos[0][2].setText("5");
            this.campos[0][3].setText("4");
            this.campos[0][4].setText("1");
            
            this.campos[1][0].setText("2");
            this.campos[1][1].setText("2");
            this.campos[1][2].setText("0");
            this.campos[1][3].setText("2");
            this.campos[1][4].setText("2");
            
            this.campos[2][0].setText("2");
            this.campos[2][1].setText("4");
            this.campos[2][2].setText("4");
            this.campos[2][3].setText("1");
            this.campos[2][4].setText("0");
            
            this.campos[3][0].setText("0");
            this.campos[3][1].setText("1");
            this.campos[3][2].setText("1");
            this.campos[3][3].setText("0");
            this.campos[3][4].setText("0");
            
            this.campos[4][0].setText("1");
            this.campos[4][1].setText("2");
            this.campos[4][2].setText("1");
            this.campos[4][3].setText("3");
            this.campos[4][4].setText("3");
            
            ///////////////////////////////////////
            this.campos[0][0].setText("1");
            this.campos[0][1].setText("2");
            this.campos[0][2].setText("7");
            this.campos[0][3].setText("3");
            this.campos[0][4].setText("0");
            
            this.campos[1][0].setText("3");
            this.campos[1][1].setText("4");
            this.campos[1][2].setText("1");
            this.campos[1][3].setText("0");
            this.campos[1][4].setText("2");
            
            this.campos[2][0].setText("2");
            this.campos[2][1].setText("3");
            this.campos[2][2].setText("6");
            this.campos[2][3].setText("0");
            this.campos[2][4].setText("0");
            
            this.campos[3][0].setText("0");
            this.campos[3][1].setText("6");
            this.campos[3][2].setText("1");
            this.campos[3][3].setText("1");
            this.campos[3][4].setText("0");
            
            this.campos[4][0].setText("2");
            this.campos[4][1].setText("0");
            this.campos[4][2].setText("0");
            this.campos[4][3].setText("4");
            this.campos[4][4].setText("5");
            
            
            this.campos[0][0].setText("5");
            this.campos[0][1].setText("1");
            this.campos[0][2].setText("1");
            this.campos[0][3].setText("3");
            this.campos[0][4].setText("2");
            
            this.campos[1][0].setText("0");
            this.campos[1][1].setText("1");
            this.campos[1][2].setText("3");
            this.campos[1][3].setText("3");
            this.campos[1][4].setText("4");
            
            this.campos[2][0].setText("2");
            this.campos[2][1].setText("5");
            this.campos[2][2].setText("4");
            this.campos[2][3].setText("3");
            this.campos[2][4].setText("0");
            
            this.campos[3][0].setText("2");
            this.campos[3][1].setText("2");
            this.campos[3][2].setText("3");
            this.campos[3][3].setText("4");
            this.campos[3][4].setText("4");
            
            this.campos[4][0].setText("6");
            this.campos[4][1].setText("2");
            this.campos[4][2].setText("0");
            this.campos[4][3].setText("0");
            this.campos[4][4].setText("1");
        }
        
        if(noElementos==4)
        {
            this.campos[0][0].setText("1");
            this.campos[0][1].setText("3");
            this.campos[0][2].setText("1");
            this.campos[0][3].setText("3");
            
            this.campos[1][0].setText("3");
            this.campos[1][1].setText("1");
            this.campos[1][2].setText("3");
            this.campos[1][3].setText("0");
            
            this.campos[2][0].setText("4");
            this.campos[2][1].setText("0");
            this.campos[2][2].setText("1");
            this.campos[2][3].setText("4");
            
            this.campos[3][0].setText("2");
            this.campos[3][1].setText("3");
            this.campos[3][2].setText("1");
            this.campos[3][3].setText("1");
        }
        else if(noElementos == 6){
            this.campos[0][0].setText("2");
            this.campos[0][1].setText("3");
            this.campos[0][2].setText("2");
            this.campos[0][3].setText("0");
            this.campos[0][4].setText("8");
            this.campos[0][5].setText("3");
            
            this.campos[1][0].setText("1");
            this.campos[1][1].setText("2");
            this.campos[1][2].setText("5");
            this.campos[1][3].setText("0");
            this.campos[1][4].setText("0");
            this.campos[1][5].setText("2");
            
            this.campos[2][0].setText("0");
            this.campos[2][1].setText("8");
            this.campos[2][2].setText("0");
            this.campos[2][3].setText("1");
            this.campos[2][4].setText("3");
            this.campos[2][5].setText("5");
            
            this.campos[3][0].setText("4");
            this.campos[3][1].setText("0");
            this.campos[3][2].setText("2");
            this.campos[3][3].setText("0");
            this.campos[3][4].setText("2");
            this.campos[3][5].setText("1");
            
            this.campos[4][0].setText("9");
            this.campos[4][1].setText("0");
            this.campos[4][2].setText("5");
            this.campos[4][3].setText("0");
            this.campos[4][4].setText("3");
            this.campos[4][5].setText("2");
            
            this.campos[5][0].setText("1");
            this.campos[5][1].setText("8");
            this.campos[5][2].setText("0");
            this.campos[5][3].setText("6");
            this.campos[5][4].setText("0");
            this.campos[5][5].setText("4");
            
            
            this.campos[0][0].setText("2");
            this.campos[0][1].setText("8");
            this.campos[0][2].setText("2");
            this.campos[0][3].setText("0");
            this.campos[0][4].setText("7");
            this.campos[0][5].setText("3");
            
            this.campos[1][0].setText("1");
            this.campos[1][1].setText("2");
            this.campos[1][2].setText("5");
            this.campos[1][3].setText("0");
            this.campos[1][4].setText("0");
            this.campos[1][5].setText("2");
            
            this.campos[2][0].setText("0");
            this.campos[2][1].setText("8");
            this.campos[2][2].setText("5");
            this.campos[2][3].setText("0");
            this.campos[2][4].setText("3");
            this.campos[2][5].setText("8");
            
            this.campos[3][0].setText("4");
            this.campos[3][1].setText("0");
            this.campos[3][2].setText("2");
            this.campos[3][3].setText("5");
            this.campos[3][4].setText("2");
            this.campos[3][5].setText("1");
            
            this.campos[4][0].setText("9");
            this.campos[4][1].setText("0");
            this.campos[4][2].setText("5");
            this.campos[4][3].setText("0");
            this.campos[4][4].setText("5");
            this.campos[4][5].setText("2");
            
            this.campos[5][0].setText("1");
            this.campos[5][1].setText("8");
            this.campos[5][2].setText("0");
            this.campos[5][3].setText("6");
            this.campos[5][4].setText("0");
            this.campos[5][5].setText("4");
        }
    }
}//GEN-LAST:event_btnGenerar_Click

private void btnInicio_Click(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnInicio_Click
// TODO add your handling code here:
    int[][] matriz;
    int[][] matrizPesos;
    
    Etiquetado etiq = new Etiquetado();
    Matriz m = new Matriz(this.campos.length);
    HungarianAlgorithm hun = new HungarianAlgorithm();
    
    if(this.campos.length > 0)
    {
        matriz = new int[this.campos.length + 1][this.campos[0].length  + 1];
        matrizPesos = new int[this.campos.length][this.campos.length]; 
        
        for(int i = 0; i < this.campos.length; i++)
        {
            for(int j = 0; j < this.campos[0].length; j++)
            {
                matriz[i][j] = Integer.parseInt(this.campos[i][j].getText());
                matrizPesos[i][j] = matriz[i][j] * (-1);
            }
        }

        etiq.Etiquetar(matriz);
        //m.ImprimirMatriz(matriz);
        m.GenerarGrafo(matriz);
        m.GenerarMatching(matriz);
        
        //if(m.IsConvex())
        if(true)
        {
            int noSaturadoActual = 0;

            // Realizar el paso 2
            Paso2 paso2 = new Paso2();

            while(!m.IsComplete())
            {
                // Tomar el primer elemento no saturado, los no saturados son 
                // de la partición X
                noSaturadoActual = m.NoSaturados()[0];
                paso2.Iniciar(m, noSaturadoActual, matriz);
            }

            //m.ImprimirMatriz(m.getMatrizAdyacencia());
            //m.ImprimirMatriz(m.getMatrizMatchig());
        }
        else
        {
            JOptionPane.showMessageDialog(null, "Este no es un grafo conexo, no se puede aplicar el algoritmo");
        }
        
        int[] resultado = hun.FindAssignments(matrizPesos);
        int[][] resultadoMatriz = new int[resultado.length][resultado.length];
        
        for(int i = 0; i < resultado.length; i++){
            //System.out.print(resultado[i] + " , ");
            resultadoMatriz[i][resultado[i]] = 1;
        }
        
        System.out.println(this.ObtenerValorTotal(m.getMatrizMatchig(), matriz));
        System.out.println(this.ObtenerValorTotal(resultadoMatriz, matriz));
        
        //m.ImprimirMatriz(resultadoMatriz);
        //m.ImprimirMatriz(m.getMatrizAdyacencia());
        
        if(this.ObtenerValorTotal(m.getMatrizMatchig(), matriz) 
                < this.ObtenerValorTotal(resultadoMatriz, matriz)){
            m.setMatrizMatchig(resultadoMatriz);
        }
        
        pintar(m, matriz);
    }
}//GEN-LAST:event_btnInicio_Click

public int ObtenerValorTotal(int [][] matMatching, int[][] matrizPesos){
    int contador = 0;
    
    for(int i = 0; i < matMatching.length; i++){
        for(int j = 0; j < matMatching.length; j++){
            if(matMatching[i][j] == 1)
                contador += matrizPesos[i][j];
        }
    }
    
    return contador;
}

public void pintar(Matriz m, int[][] matriz){
    int x = 50, y=0, sum = 0;
    int num = m.getMatrizAdyacencia().length;
    
    BufferedImage img = new BufferedImage(100*num, 300, BufferedImage.TYPE_INT_RGB);
    Graphics g = img.getGraphics();
    
    g.setColor(Color.white);
    g.fillRect(0, 0, 100*num, 300);
    g.setColor(Color.black);
    
    
    for(int i = 0; i < num;i++){
        for(int j = 0; j < num;j++){
            if(m.getMatrizMatchig()[i][j] == 1){
                g.setColor(Color.red);
                g.drawLine(((i*100)+50), 50, ((j*100)+50), 250);
                sum += matriz[i][j];
                g.setColor(Color.black);
            }
            else if(m.getMatrizAdyacencia()[i][j] == 1){
                g.drawLine(((i*100)+50), 50, ((j*100)+50), 250);
            }
        }
    }
    
    for(int p = 0; p < num;p++){
        y = p+1;
        g.drawString("X" + y, x-3, 47);
        g.fillOval(x-3, 47, 7, 7);
        g.fillOval(x-3, 247, 7, 7);
        g.drawString("Y" + y, x-3, 264);
        x += 100;
    }
    
    g.dispose();
    JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(img)),"El valor óptimo: " + sum,JOptionPane.INFORMATION_MESSAGE);
}

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnGenerar;
    private javax.swing.JButton btnIniciar;
    private javax.swing.JLayeredPane jLayeredPane1;
    private javax.swing.JLayeredPane jLayeredPane2;
    private javax.swing.JLabel lblNoElementos;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JSpinner spNoElementos;
    // End of variables declaration//GEN-END:variables

    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;

    private JDialog aboutBox;
    
    private LinkedList<JTextField> mTextField = new LinkedList<JTextField>();
    private JTextField[][] campos;
}
